#ifndef DSPSIMULATOR_DSPSIMULATOR_H
#define DSPSIMULATOR_DSPSIMULATOR_H

#include <vector>
#include <queue>
#include <simulator/instFetcher.h>
#include <simulator/simulator.h>
#include <simulator/command/command.h>
#include <simulator/instruction/instruction.h>
#include <simulator/instruction/delayInstruction.h>
#include <dspSimulator/targetMachine/interruptHandle.h>
#include <dspSimulator/dspSimulator/dspInstFetcher.h>
#include <dspSimulator/targetMachine/sploopbuffer.h>
#include <dspSimulator/targetMachine/dspMachine.h>
#include <dspSimulator/command/next.h>
#include <dspSimulator/command/printARegs.h>
#include <dspSimulator/command/printBRegs.h>
#include <dspSimulator/command/continue.h>
#include <dspSimulator/command/printAReg.h>
#include <dspSimulator/command/printBReg.h>
#include <dspSimulator/command/printCReg.h>
#include <dspSimulator/command/breakPoint.h>
#include <dspSimulator/command/exit.h>
#include <dspSimulator/command/watchMemory.h>
#include <dspSimulator/command/snapshot.h>
#include <dspSimulator/command/saveAndrestore.h>

class DSPSimulator : public Simulator {
    friend class NextCommand;

    friend class PrintARegsCommand;

    friend class PrintBRegsCommand;

    friend class ContinueCommand;

    friend class PrintARegCommand;

    friend class PrintBRegCommand;

    friend class PrintCRegCommand;

    friend class BreakPointCommand;

    friend class WatchMemoryCommand;

    friend class SaveAndRestoreCommand;

private:
    std::shared_ptr<SPLoopBuffer> m_sploopBuffer;
    std::shared_ptr<InterruptHandle> m_interruptHandle;

    u64 m_numOfInstruction;         // 记录当前已经完成执行的指令数
    u64 m_numOfInsertNOP;           // 记录插入在执行包之后的nop指令数

public:
    DSPSimulator(std::shared_ptr<TargetMachine> targetMachine, std::shared_ptr<InstFetcher> instFetcher,
                 std::shared_ptr<LLVMJit> llvmJit) :
            Simulator(targetMachine, instFetcher, llvmJit) {
        m_sploopBuffer = std::make_shared<SPLoopBuffer>(std::dynamic_pointer_cast<DspMachine>(targetMachine));
        m_interruptHandle = std::make_shared<InterruptHandle>(std::dynamic_pointer_cast<DspMachine>(targetMachine));
        m_numOfInsertNOP = 0;
        m_numOfInstruction = 0;
    }

    ~DSPSimulator() override = default;

    void run() override;

    /**
     * 添加目标机器支持的指令原型
     */
    void addAllInstructionProto() override;

protected:

    /**
    * 取指函数
    * @return 当前周期取指器取出的指令数据集合
    */
    std::vector<std::shared_ptr<InstInfo>> fetch() override;

    /**
    * 根据指令数据集合解码出一系列对应的指令对象
    * @param instInfo 指令数据集合
    * @return 解码出的一系列指令
    */
    std::vector<std::shared_ptr<Instruction>> decode(std::vector<std::shared_ptr<InstInfo>> instInfos) override;

    /**
    * 执行指令
    * @param instruction 一系列指令
    */
    void execute(std::vector<std::shared_ptr<Instruction>> instructions) override;

    /**
     * 该函数用于添加全局变量，以供ir函数执行
     */
    void addGlobalVariable(llvm::LLVMContext *llvmContext, llvm::Module *llvmModule) override;

    /**
    * 该函数用于添加全局变量的映射，用于将全局变量映射到正确的地址上
     */
    void addGlobalMapping(std::shared_ptr<llvm::ExecutionEngine> executionEngine) override;

    void executeInsertNOP(u32 nopNum);

    void beforeNextExecutePacketExecute(std::vector<std::shared_ptr<Instruction>> &executePacket);

    void beforeInstructionExecute(std::vector<std::shared_ptr<Instruction>> &executePacket);

    void afterInstructionExecute(std::vector<std::shared_ptr<Instruction>> &executePacket);

    std::shared_ptr<Snapshot> createSnapshot();

    void restore(std::shared_ptr<Snapshot> snapshot);
};


#endif //DSPSIMULATOR_DSPSIMULATOR_H
